{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from __future__ import print_function\n",
    "import numpy as np\n",
    "import keras\n",
    "from keras.models import Sequential\n",
    "from keras.layers import Dense, Dropout, Flatten, Activation\n",
    "from keras.layers import Conv2D, MaxPooling2D\n",
    "from keras import backend as K\n",
    "from keras.layers.normalization import BatchNormalization\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "def loadImageFile(fileimage):\n",
    "    f = open(fileimage, \"rb\")\n",
    "\n",
    "    f.read(16)\n",
    "    pixels = 28*28\n",
    "    images_arr = []\n",
    "    \n",
    "    while True:\n",
    "        try:\n",
    "            img = []\n",
    "            for j in range(pixels):\n",
    "                pix = ord(f.read(1))\n",
    "                img.append(pix / 255)\n",
    "            images_arr.append(img)\n",
    "        except:\n",
    "            break\n",
    "\n",
    "    f.close()\n",
    "    image_sets = np.array(images_arr)\n",
    "    return image_sets"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def loadLabelFile(filelabel):\n",
    "    f = open(filelabel, \"rb\")\n",
    "    f.read(8)\n",
    "\n",
    "    labels_arr = []\n",
    "\n",
    "    while True:\n",
    "        row = [0 for x in range(10)]\n",
    "        try:\n",
    "            label = ord(f.read(1))\n",
    "            row[label] = 1\n",
    "            labels_arr.append(row)\n",
    "        except:\n",
    "            break\n",
    "\n",
    "    f.close()\n",
    "    label_sets = np.array(labels_arr)\n",
    "    return label_sets"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_images = loadImageFile(\"/MNIST/train-images-idx3-ubyte\")\n",
    "train_labels = loadLabelFile(\"/MNIST/train-labels-idx1-ubyte\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "test_images = loadImageFile(\"/MNIST/t10k-images-idx3-ubyte\")\n",
    "test_labels = loadLabelFile(\"/MNIST/t10k-labels-idx1-ubyte\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_train = train_images.reshape(train_images.shape[0], 28, 28, 1)\n",
    "x_test = test_images.reshape(test_images.shape[0], 28, 28, 1)\n",
    "\n",
    "y_train = train_labels\n",
    "y_test = test_labels"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = Sequential()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.add(Conv2D(32, (3, 3), input_shape=(28,28,1)))\n",
    "model.add(Activation('relu'))\n",
    "BatchNormalization(axis=-1)\n",
    "model.add(Conv2D(32, (3, 3)))\n",
    "model.add(Activation('relu'))\n",
    "model.add(MaxPooling2D(pool_size=(2,2)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "BatchNormalization(axis=-1)\n",
    "model.add(Conv2D(64,(3, 3)))\n",
    "model.add(Activation('relu'))\n",
    "BatchNormalization(axis=-1)\n",
    "model.add(Conv2D(64, (3, 3)))\n",
    "model.add(Activation('relu'))\n",
    "model.add(MaxPooling2D(pool_size=(2,2)))\n",
    "\n",
    "model.add(Flatten())\n",
    "# Fully connected layer\n",
    "\n",
    "BatchNormalization()\n",
    "model.add(Dense(512))\n",
    "model.add(Activation('relu'))\n",
    "BatchNormalization()\n",
    "model.add(Dropout(0.2))\n",
    "model.add(Dense(10))\n",
    "\n",
    "model.add(Activation('softmax'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.compile(loss=keras.losses.categorical_crossentropy,\n",
    "              optimizer=keras.optimizers.Adam(),\n",
    "              metrics=['accuracy'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/10\n",
      "480/480 - 28s - loss: 0.1796 - accuracy: 0.9456 - val_loss: 0.0606 - val_accuracy: 0.9819\n",
      "Epoch 2/10\n",
      "480/480 - 28s - loss: 0.0458 - accuracy: 0.9856 - val_loss: 0.0374 - val_accuracy: 0.9893\n",
      "Epoch 3/10\n",
      "480/480 - 28s - loss: 0.0301 - accuracy: 0.9907 - val_loss: 0.0434 - val_accuracy: 0.9880\n",
      "Epoch 4/10\n",
      "480/480 - 28s - loss: 0.0229 - accuracy: 0.9928 - val_loss: 0.0416 - val_accuracy: 0.9885\n",
      "Epoch 5/10\n",
      "480/480 - 28s - loss: 0.0184 - accuracy: 0.9939 - val_loss: 0.0310 - val_accuracy: 0.9911\n",
      "Epoch 6/10\n",
      "480/480 - 28s - loss: 0.0143 - accuracy: 0.9953 - val_loss: 0.0336 - val_accuracy: 0.9908\n",
      "Epoch 7/10\n",
      "480/480 - 28s - loss: 0.0139 - accuracy: 0.9953 - val_loss: 0.0393 - val_accuracy: 0.9904\n",
      "Epoch 8/10\n",
      "480/480 - 28s - loss: 0.0097 - accuracy: 0.9968 - val_loss: 0.0405 - val_accuracy: 0.9906\n",
      "Epoch 9/10\n",
      "480/480 - 28s - loss: 0.0114 - accuracy: 0.9961 - val_loss: 0.0347 - val_accuracy: 0.9913\n",
      "Epoch 10/10\n",
      "480/480 - 28s - loss: 0.0088 - accuracy: 0.9971 - val_loss: 0.0346 - val_accuracy: 0.9922\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<tensorflow.python.keras.callbacks.History at 0x7fd31bcd7c18>"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.fit(x_train, y_train,\n",
    "          batch_size=100,\n",
    "          epochs=10,\n",
    "          verbose=2,\n",
    "          validation_split=0.2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "313/313 [==============================] - 1s 3ms/step - loss: 0.0245 - accuracy: 0.9924\n",
      "Test loss: 0.024507645517587662\n",
      "Test accuracy: 0.9923999905586243\n"
     ]
    }
   ],
   "source": [
    "score = model.evaluate(x_test, y_test, verbose=1)\n",
    "\n",
    "print('Test loss:', score[0])\n",
    "print('Test accuracy:', score[1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "# import os\n",
    "# os.mkdir(\"../output\")\n",
    "# model.save(\"../output/model.h5\")\n",
    "model.save_weights(\"/MNIST/weights.h5\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "model_json = model.to_json()\n",
    "with open(\"/MNIST/model.json\", \"w\") as json_file:\n",
    "    json_file.write(model_json)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
